package com.demo.redis.service;

import cn.hutool.core.lang.UUID;
import com.demo.redis.domain.UserModel;
import com.demo.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserService {

    @Autowired
    UserModel userModel;

    @Autowired
    RedisUtils redisUtils;

    public void info() {
        System.out.println(userModel.toString());
    }

    public String lock() {
        String lockkey = "lockkey";
        boolean lock = redisUtils.tryLock(lockkey);
        if (! lock) {
            return "get lock failed";
        }
        try {
            log.info("do sth");
            Thread.sleep(5000);
            return "success";
        } catch (Exception e) {
            e.printStackTrace();
            return "app exception";
        } finally {
            redisUtils.unlock(lockkey);
        }
    }

    /**
     * 错误的上锁方式
     * @return
     */
    public String wronglock() {
        String lockkey = "wronglock";

        try {
            // 如果lock在try内部, 并发的时候会执行finally
            // 如果 finally 不判断值是否属于当前线程
            // 会导致释放了别的线程的锁，因为他们的key值是一样的
            boolean lock = redisUtils.tryLock(lockkey);
            if (! lock) {
                return "get lock failed";
            }

            log.info("do sth");
            Thread.sleep(50000);
            return "success";
        } catch (Exception e) {
            e.printStackTrace();
            return "app exception";
        } finally {
            log.info(String.format("释放锁 %s", lockkey));
            redisUtils.unlock(lockkey);
        }
    }

    /**
     * 正确的上锁方式
     * @return
     */
    public String rightlock() {
        String lockkey = "rightlock";
        String lockvalue = UUID.fastUUID().toString();
        log.info(String.format("锁 %s %s", lockkey, lockvalue));
        try {
            // 上锁20秒
            boolean lock = redisUtils.lock(lockkey, lockvalue, 20, TimeUnit.SECONDS);
            System.out.println(String.format("%s %s %s", lockkey, lockvalue,String.valueOf(lock)));
            if (! lock) {
                return "get lock failed";
            }

            log.info("do sth");
            Thread.sleep(10000);
            return "success";
        } catch (Exception e) {
            e.printStackTrace();
            return "app exception";
        } finally {
            redisUtils.unlock(lockkey, lockvalue);
        }
    }
}
